
/*
    Software License

    Copyright (C) 2021-05-24  Xoronos

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

/*
    Liabilities

    The software is provided "AS IS" without any warranty of any kind, either expressed,
    implied, or statutory, including, but not limited to, any warranty that the software
    will conform to specifications, any implied warranties of merchantability, fitness
    for a particular purpose, and freedom from infringement, and any warranty that the
    documentation will conform to the software, or any warranty that the software will
    be error free.

    In no event shall Xoronos be liable for any damages, including, but not limited to,
    direct, indirect, special or consequential damages, arising out of, resulting from,
    or in any way connected with this software, whether or not based upon warranty,
    contract, tort, or otherwise, whether or not injury was sustained by persons or
    property or otherwise, and whether or not loss was sustained from, or arose out of
    the results of, or use of, the software or services provided hereunder.

    To request the provided software under a different license you can contact us at
    support@xoronos.com
*/

#include "xrn_core_backend.h"

int dump_xnum( xnum_t num1,
               xrn_lib_xtype_t type,
               uint8_t crc_bytes, uint8_t state_size, FILE * fp, xrn_crypto_extra_settings_t settings
 )
{

    uint32_t crc32_local;
    xrn_encoding_param_t enc_param;
    int ret, final_ret;

    final_ret = XSUCCESS;

    ret = xrn_dump_header_file( fp, type, crc_bytes, state_size, &enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 200, XERR_GENERAL_MSG );
        return ret;
    }

    if ( 1 != xrn_fwrite_encoder( &num1, sizeof( num1 ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2140, XERR_IO_MSG );
        return XERR_IO;
    }

    crc32_local = 0xffffffff;
    xrn_crc32( ( uint8_t * ) & num1, sizeof( num1 ), &crc32_local );

    if ( 1 != xrn_fwrite_encoder( &crc32_local, sizeof( crc32_local ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2141, XERR_IO_MSG );
        return XERR_IO;
    }

    return final_ret;

}

int load_xnum( xnum_t * xnum1,
               uint8_t * crc_bytes,
               xrn_lib_xtype_t * type, xrn_lib_xtype_t exp_type, uint8_t * state_size,
               FILE * fp, xrn_crypto_extra_settings_t settings
 )
{

    xnum_t xnum1_local;
    uint32_t crc32_local;
    uint32_t crc32_stored;
    int ret, final_ret;
    xrn_encoding_param_t enc_param;
    uint32_t reserved_0, reserved_1;

    if ( ( fp == NULL ) || ( xnum1 == NULL ) || ( type == NULL ) || ( crc_bytes == NULL ) ) {
        XPRINT_ERR( 2142, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    ret =
        xrn_load_header_file( fp, crc_bytes, type, exp_type, state_size,
                              &reserved_0, &reserved_1, &enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 199, XERR_GENERAL_MSG );
        return ret;
    }

    if ( xrn_fread_decoder( &xnum1_local, sizeof( xnum1_local ), 1, fp, &enc_param ) != 1 ) {
        XPRINT_ERR( 2151, XERR_IO_MSG );
        return XERR_IO;
    }

    crc32_local = 0xffffffff;
    xrn_crc32( ( uint8_t * ) & xnum1_local, sizeof( xnum1_local ), &crc32_local );

    if ( xrn_fread_decoder( &crc32_stored, sizeof( crc32_stored ), 1, fp, &enc_param ) != 1 ) {
        XPRINT_ERR( 2152, XERR_IO_MSG );
        return XERR_IO;
    }

    if ( crc32_stored != crc32_local ) {
        XPRINT_ERR( 2153, XERR_CRC_MSG );
        return XERR_CRC;
    }

    *xnum1 = xnum1_local;

    return final_ret;

}

void gaussian_elimination( xrn_base_t * a
 )
{
    xnum_t tmp;

    uint8_t tmpsig;
    int j, i;
    XINT_TYPE k;
    uint8_t unpacksig[XNBITS];

    for ( i = 0; i < XNBITS; i++ ) {
        unpacksig[i] = a->sign_vector.xnum[i / XBASE_NUM] >> ( i % XBASE_NUM ) & 1;
    }

    for ( i = 0; i < XNBITS; i++ ) {
        k = ( XINT_TYPE ) 1 << ( i % XBASE_NUM );
        j = ( int ) ( a->base_matrix.xmat[i].xnum[i / XBASE_NUM] & k );
        if ( j == 0 ) {
            for ( j = i + 1; j < XNBITS; j++ ) {
                k = ( XINT_TYPE ) 1 << ( i % XBASE_NUM );
                if ( ( a->base_matrix.xmat[j].xnum[i / XBASE_NUM] & k ) ) {
                    tmp = a->base_matrix.xmat[i];
                    a->base_matrix.xmat[i] = a->base_matrix.xmat[j];
                    a->base_matrix.xmat[j] = tmp;

                    tmpsig = unpacksig[j];
                    unpacksig[j] = unpacksig[i];
                    unpacksig[i] = tmpsig;

                    break;
                }

            }

        }

        for ( j = i + 1; j < XNBITS; j++ ) {
            k = ( XINT_TYPE ) 1 << ( i % XBASE_NUM );
            if ( a->base_matrix.xmat[j].xnum[i / XBASE_NUM] & k ) {
                X_XOR2( a->base_matrix.xmat[i], a->base_matrix.xmat[j] );
                unpacksig[j] ^= unpacksig[i];
            }

        }

    }

    for ( i = XNBITS - 1; i > 0; i-- ) {
        for ( j = i - 1; j >= 0; j-- ) {
            k = ( XINT_TYPE ) 1 << ( i % XBASE_NUM );
            if ( a->base_matrix.xmat[j].xnum[i / XBASE_NUM] & k ) {
                X_XOR2( a->base_matrix.xmat[i], a->base_matrix.xmat[j] )
                    unpacksig[j] ^= unpacksig[i];
            }

        }

    }

    for ( int lu = 0; lu < XNBITS_NUM; lu++ )
        a->sign_vector.xnum[lu] = 0;

    for ( i = 0; i < XNBITS; i++ ) {
        a->sign_vector.xnum[i / XBASE_NUM] |= ( ( XINT_TYPE ) ( unpacksig[i] ) << ( i % XBASE_NUM ) );
    }

}

void xor_of_bases( xrn_base_t * xb, xrn_base_t * x2, xrn_base_t * dst
 )
{
    for ( int i = 0; i < ( sizeof( xnum_t ) * 8 ); i++ ) {
        X_XOR3( xb->base_matrix.xmat[i], x2->base_matrix.xmat[i], dst->base_matrix.xmat[i] );
    }

    X_XOR3( xb->sign_vector, x2->sign_vector, dst->sign_vector );
}

void xor_xrn_matrix( xrn_base_t * a, xrn_base_t * b, xrn_base_t * c
 )
{
    for ( int i = 0; i < ( sizeof( xnum_t ) * 8 ); i++ ) {
        X_XOR3( a->base_matrix.xmat[i], b->base_matrix.xmat[i], c->base_matrix.xmat[i] );
    }

    X_XOR3( a->sign_vector, b->sign_vector, c->sign_vector );
}

void xgenesis_base_v2m( xgenesis_base_t * obase, xmat_t * res
 )
{

    int vi, vj;
    int mi, mj;
    int tmp;

    XBIT_TYPE bit;

    xrn_initialize_mat( res );

    mi = 0;
    mj = 0;

    // for all the bits in the origin base excluding the last bit
    for ( vi = 0; vi < XNBYTES_ORIGIN; vi++ ) {
        for ( vj = 0; vj < 8; vj++ ) {

            // the current bit in the origin base
            bit = ( obase->base_vector[vi] >> vj ) & 0x01;

            BIT_SETVAL( res->xmat[mi], mj, bit );

            mj++;
            if ( ( mj == ( sizeof( xnum_t ) * 8 ) ) && ( mi < ( sizeof( xnum_t ) * 8 ) ) ) {
                mi++;
                mj = mi;
            }

        }

    }

    // set known bits
    tmp = ( ( sizeof( xnum_t ) * 8 ) - 1 );
    BIT_SETVAL( res->xmat[0], tmp, true );
    for ( mi = 1; mi < ( sizeof( xnum_t ) * 8 ); mi++ ) {
        mj = mi - 1;
        BIT_SETVAL( res->xmat[mi], mj, true );
    }

    return;
}

void xgenesis_base_m2v( xmat_t * matrix, xgenesis_base_t * obase
 )
{

    int vi, vj;
    int mi, mj;
    XBIT_TYPE bit;

    xrn_initialize_genesis_base( obase );

    vi = 0;
    vj = 0;

    // index of the matrix
    for ( mi = 0; mi < ( sizeof( xnum_t ) * 8 ); mi++ ) {
        for ( mj = mi; mj < ( sizeof( xnum_t ) * 8 ); mj++ ) {

            bit = BIT_GET( matrix->xmat[mi], mj );

            // writing in the origin base
            obase->base_vector[vi] = ( uint8_t ) ( obase->base_vector[vi] | ( bit << vj ) );

            vj++;
            if ( vj == 8 ) {
                vj = 0;
                vi++;
            }

        }

    }

    return;
}

void xgenesis_base_2_xrn_matrix( xgenesis_base_t * ob,
                                 xnum_t * change_of_base, xnum_t * change_of_sign, xrn_matrix_t * xml
 )
{

    xrn_base_t xb;
    xrn_matrix_t xm_int;
    xmat_t xmat;
    xnum_t zero;

    xnum_t cob;
    xnum_t cos;
    int i;

    // copy internal matrix
    xm_int = *xml;

    xrn_initialize_num( &zero );

    // get pointers values
    cob = *change_of_base;
    cos = *change_of_sign;

    // convert origin base to a xoron base 
    xgenesis_base_v2m( ob, &xmat );

    // initialize xoron base with a random sign
    xb.base_matrix = xmat;
    xb.sign_vector = zero;

    // change the xoron base
    xrn_base_number_mul( &xb, &cob, &xb );

    // change of sign
    xb.sign_vector = cos;

    // create a xoron matrix
    xm_int.xrn_dead_code = zero;

    for ( i = 0; i < ( sizeof( xnum_t ) * 8 ); i++ ) {
        xm_int.xvector[i].xbase = xb;
        xm_int.xvector[i].entry_point = zero;
        xrn_doubling( &xb, &xb );
    }

    // compute dead code and entry points
    update_xrn_matrix( &xm_int, xml );

    return;
}

void update_xrn_matrix( xrn_matrix_t * src, xrn_matrix_t * dst
 )
{

    xnum_t dc;                  // dead code
    xnum_t dci;
    xnum_t distance;
    xnum_t entry_point;
    uint8_t constant_execution, force_linearity, xrn_check_sparsity;

    int i;
    xrn_matrix_t xml;

    constant_execution = 0;
    force_linearity = 0;
    xrn_check_sparsity = 0;

    // calculate the dead code
    i = 0;
    xrn_dead_code( &src->xvector[i].xbase, &dc );

    // invert dead code
    X_INV2( dc, dci );

    // update the destination matrix
    xml.xrn_dead_code = dc;
    for ( i = 0; i < ( sizeof( xnum_t ) * 8 ); i++ ) {
        xml.xvector[i].entry_point = dc;
        xml.xvector[i].xbase = src->xvector[i].xbase;
    }

    // initialize distance with all 1
    xrn_initialize_num( &distance );
    X_INV2( distance, distance );

    // update entry points
    for ( i = 0; i < ( sizeof( xnum_t ) * 8 ); i++ ) {

        // updated distance
        BIT_SETVAL( distance, i, false );

        xrn_matrix_traverse( &xml, &dci, &distance, &entry_point, &constant_execution, &force_linearity,
                             &xrn_check_sparsity );

        // updated distance
        BIT_SETVAL( distance, i, true );

        // save results
        xml.xvector[i].entry_point = entry_point;

    }

    *dst = xml;

    return;
}

void const_distance_eval( xnum_t distance, uint8_t * const_dist
 )
{

    int i, j;
    XBIT_TYPE bit0, bit1;

    for ( i = 0; i < ( sizeof( xnum_t ) * 8 ); i++ ) {

        j = i;
        bit1 = BIT_GET( distance, i );

        if ( ( j - 1 ) < 0 ) {

            j = XNBITS - 1;

        } else {

            j--;

        }

        bit0 = BIT_GET( distance, j );

        if ( ( bit1 == 0 ) && ( bit0 == 0 ) ) {
            const_dist[i] = 1;
        } else if ( ( bit1 == 0 ) && ( bit0 == 1 ) ) {
            const_dist[i] = 2;
        } else if ( ( bit1 == 1 ) && ( bit0 == 0 ) ) {
            const_dist[i] = 0;
        } else if ( ( bit1 == 1 ) && ( bit0 == 1 ) ) {
            const_dist[i] = 1;
        }

    }

    return;

}

void print_xheader( xrn_crypto_lib_header_t header
 )
{

    int nbits;
    uint8_t crc_bytes;
    int ret;
    char buff[256];

    xrn_load_sub_type( header.type, &crc_bytes, &nbits );
    ret = xrn_convert_libtype_to_string( ( uint8_t ) ( header.type >> 3 ), buff, 256 );

    if ( ret != XSUCCESS ) {
        return;
    }

    printf( "header.magic_number = %u\n", header.magic_number );
    printf( "header.version = %u\n", header.version );
    printf( "header.reserved_0 = %u\n", header.reserved_0 );
    printf( "header.reserved_1 = %u\n", header.reserved_1 );
    printf( "header.type = %s\n", buff );

    printf( "header.crc_bytes = %u\n", crc_bytes );
    printf( "header.nbits = %u\n", nbits );

    printf( "header.state_size = %u\n", header.state_size );
    printf( "header.crc16 = %u\n", header.crc16 );

    return;

}

void print_xrn_crypto_extra_settings( xrn_crypto_extra_settings_t settings
 )
{

    printf( "settings.rnd_str = %s\n", settings.rnd_str );
    printf( "settings.crc_bytes = %3d\n", settings.crc_bytes );
    printf( "settings.state_size = %3d\n", settings.state_size );
    printf( "settings.thread_enable = %3d\n", settings.thread_enable );
    printf( "settings.const_exec_time = %3d\n", settings.const_exec_time );
    printf( "settings.component_id = %u\n", settings.component_id );

    if ( settings.encoding_settings.i_settings.mode == 0 ) {
        printf( "settings.encoding_settings.i_settings.mode = %3d -> std_parameters\n",
                settings.encoding_settings.i_settings.mode );
    } else if ( settings.encoding_settings.i_settings.mode == 1 ) {
        printf( "settings.encoding_settings.i_settings.mode = %3d -> xrn_parameters\n",
                settings.encoding_settings.i_settings.mode );
    } else if ( settings.encoding_settings.i_settings.mode == 2 ) {
        printf( "settings.encoding_settings.i_settings.mode = %3d -> std_parameters_plus_password\n",
                settings.encoding_settings.i_settings.mode );
    } else if ( settings.encoding_settings.i_settings.mode == 3 ) {
        printf( "settings.encoding_settings.i_settings.mode = %3d -> xrn_parameters_plus_password\n",
                settings.encoding_settings.i_settings.mode );
    } else if ( settings.encoding_settings.i_settings.mode == 4 ) {
        printf( "settings.encoding_settings.i_settings.mode = %3d -> no_encoding\n",
                settings.encoding_settings.i_settings.mode );
    } else {
        printf( "error in the settings.encoding_settings.i_settings.mode = %3d ",
                settings.encoding_settings.i_settings.mode );
    }

    if ( settings.encoding_settings.i_settings.encoding_parameters_fp == NULL ) {
        printf( "settings.encoding_settings.i_settings.encoding_parameters_fp -> not specified\n" );
    } else {
        printf( "settings.encoding_settings.i_settings.encoding_parameters_fp -> specified\n" );
    }

    printf( "settings.encoding_settings.i_settings.password = %s\n",
            settings.encoding_settings.i_settings.password );
    printf( "settings.encoding_settings.i_settings.password_length = %d\n",
            settings.encoding_settings.i_settings.password_length );

    if ( settings.encoding_settings.i_settings.check_mode == 0 ) {
        printf( "settings.encoding_settings.i_settings.check_mode = %d -> xrn_automatic \n",
                settings.encoding_settings.i_settings.check_mode );
    } else if ( settings.encoding_settings.i_settings.check_mode == 1 ) {
        printf( "settings.encoding_settings.i_settings.check_mode = %d -> xrn_manual \n",
                settings.encoding_settings.i_settings.check_mode );
    } else {
        printf( "error in the settings.encoding_settings.i_settings.check_mode = %3d ",
                settings.encoding_settings.i_settings.check_mode );
    }

    printf( "settings.encoding_settings.i_settings.check_running_error_en = %d\n",
            settings.encoding_settings.i_settings.check_running_error_en );
    printf( "settings.encoding_settings.i_settings.check_disparity_error_en = %d\n",
            settings.encoding_settings.i_settings.check_disparity_error_en );
    printf( "settings.encoding_settings.i_settings.max_consecutives_01s_threshold_error = %d\n",
            settings.encoding_settings.i_settings.max_consecutives_01s_threshold_error );
    printf( "settings.encoding_settings.i_settings.max_consecutives_01s_threshold_warning = %d\n",
            settings.encoding_settings.i_settings.max_consecutives_01s_threshold_warning );
    printf( "settings.encoding_settings.i_settings.max_number_of_01s_threshold_error = %d\n",
            settings.encoding_settings.i_settings.max_number_of_01s_threshold_error );
    printf( "settings.encoding_settings.i_settings.max_number_of_01s_threshold_warning = %d\n",
            settings.encoding_settings.i_settings.max_number_of_01s_threshold_warning );

    if ( settings.encoding_settings.o_settings.mode == 0 ) {
        printf( "settings.encoding_settings.o_settings.mode = %3d -> std_parameters\n",
                settings.encoding_settings.o_settings.mode );
    } else if ( settings.encoding_settings.o_settings.mode == 1 ) {
        printf( "settings.encoding_settings.o_settings.mode = %3d -> xrn_parameters\n",
                settings.encoding_settings.o_settings.mode );
    } else if ( settings.encoding_settings.o_settings.mode == 2 ) {
        printf( "settings.encoding_settings.o_settings.mode = %3d -> std_parameters_plus_password\n",
                settings.encoding_settings.o_settings.mode );
    } else if ( settings.encoding_settings.o_settings.mode == 3 ) {
        printf( "settings.encoding_settings.o_settings.mode = %3d -> xrn_parameters_plus_password\n",
                settings.encoding_settings.o_settings.mode );
    } else if ( settings.encoding_settings.o_settings.mode == 4 ) {
        printf( "settings.encoding_settings.o_settings.mode = %3d -> no_encoding\n",
                settings.encoding_settings.o_settings.mode );
    } else {
        printf( "error in the settings.encoding_settings.o_settings.mode = %3d ",
                settings.encoding_settings.o_settings.mode );
    }

    if ( settings.encoding_settings.o_settings.encoding_parameters_fp == NULL ) {
        printf( "settings.encoding_settings.o_settings.encoding_parameters_fp -> not specified\n" );
    } else {
        printf( "settings.encoding_settings.o_settings.encoding_parameters_fp -> specified\n" );
    }

    printf( "settings.encoding_settings.o_settings.password = %s\n",
            settings.encoding_settings.o_settings.password );
    printf( "settings.encoding_settings.o_settings.password_length = %d\n",
            settings.encoding_settings.o_settings.password_length );

    if ( settings.encoding_settings.o_settings.check_mode == 0 ) {
        printf( "settings.encoding_settings.o_settings.check_mode = %d -> xrn_automatic \n",
                settings.encoding_settings.o_settings.check_mode );
    } else if ( settings.encoding_settings.o_settings.check_mode == 1 ) {
        printf( "settings.encoding_settings.o_settings.check_mode = %d -> xrn_manual \n",
                settings.encoding_settings.o_settings.check_mode );
    } else {
        printf( "error in the settings.encoding_settings.o_settings.check_mode = %3d ",
                settings.encoding_settings.o_settings.check_mode );
    }

    printf( "settings.encoding_settings.o_settings.check_running_error_en = %d\n",
            settings.encoding_settings.o_settings.check_running_error_en );
    printf( "settings.encoding_settings.o_settings.check_disparity_error_en = %d\n",
            settings.encoding_settings.o_settings.check_disparity_error_en );
    printf( "settings.encoding_settings.o_settings.max_consecutives_01s_threshold_error = %d\n",
            settings.encoding_settings.o_settings.max_consecutives_01s_threshold_error );
    printf( "settings.encoding_settings.o_settings.max_consecutives_01s_threshold_warning = %d\n",
            settings.encoding_settings.o_settings.max_consecutives_01s_threshold_warning );
    printf( "settings.encoding_settings.o_settings.max_number_of_01s_threshold_error = %d\n",
            settings.encoding_settings.o_settings.max_number_of_01s_threshold_error );
    printf( "settings.encoding_settings.o_settings.max_number_of_01s_threshold_warning = %d\n",
            settings.encoding_settings.o_settings.max_number_of_01s_threshold_warning );

    return;

}

int xrn_load_header( xrn_crypto_lib_header_t header,
                     uint8_t * crc_bytes,
                     xrn_lib_xtype_t * type,
                     xrn_lib_xtype_t exp_type,
                     uint8_t * state_size, uint32_t * reserved_0, uint32_t * reserved_1
 )
{
    XPRINT_DEB(  );

    int ret, final_ret;
    int nbits;
    uint16_t crc16;
    uint8_t crc_bytes_local;
    xrn_crypto_lib_header_t header_local;

    final_ret = XSUCCESS;

    // checks on header

    header_local = header;
    header_local.crc16 = 0xffff;
    crc16 = 0xffff;
    xrn_crc16( ( uint8_t * ) & header_local, sizeof( header_local ) - 1, &crc16 );
    header_local.crc16 = crc16;

    if ( header_local.crc16 != header.crc16 ) {
        XPRINT_ERR( 240, XERR_CRC_MSG );
        return XERR_CRC;
    }

    ret = xrn_compare_version( header_local.version, header_local.reserved_1 );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 239, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_check_valid_type( ( uint8_t ) ( header_local.type >> 3 ) );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        return ret;
    }

    xrn_load_sub_type( header_local.type, &crc_bytes_local, &nbits );

    if ( header_local.magic_number != XRN_PERMUTATION_NUMBER ) {
        XPRINT_ERR( 238, XERR_MAGIC_MSG );
        return XERR_MAGIC;
    }

    if ( nbits != XNBITS ) {
        XPRINT_ERR( 155, XERR_NBITS_MSG );
        return XERR_NBITS;
    }

    if ( ( ( uint8_t ) ( header_local.type >> 3 ) ) != exp_type ) {
        XPRINT_ERR( 103, XERR_TYPE_MSG );
        return XERR_TYPE;
    }

    if ( ( header_local.state_size < XRN_MIN_ALLOWED_STATE_SIZE )
         && ( header_local.state_size > ( sizeof( xnum_t ) * 8 ) - 1 ) ) {
        XPRINT_ERR( 101, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    if ( crc_bytes_local == 0 ) {
        crc_bytes_local = 1;
    } else if ( crc_bytes_local == 1 ) {
        crc_bytes_local = 2;
    } else if ( crc_bytes_local == 2 ) {
        crc_bytes_local = 4;
    } else if ( crc_bytes_local == 3 ) {
        crc_bytes_local = 8;
    } else {
        XPRINT_ERR( 60, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    *type = header_local.type >> 3;
    *crc_bytes = crc_bytes_local;
    *state_size = header_local.state_size;
    *reserved_0 = header_local.reserved_0;
    *reserved_1 = header_local.reserved_1;

    return final_ret;

}

